#pragma once
#define CONTACTS_IP "127.0.0.1"
#define CONTACTS_PORT 8888
#include "ContactException.hpp"
#include "ContactMapper.hpp"
#include "request.pb.h"
#include "response.pb.h"
#include "Utlis.hpp"

class ContactServer
{
public:
    void printAddContactRequest(request::AddContactRequest &request) const
    {
        std::cout << "---> (ContactsServer::add) AddContactRequest:" << std::endl;
        std::cout << "姓名：" << request.name() << std::endl;
        std::cout << "年龄：" << request.age() << std::endl;
        switch (request.gender_case())
        {
        case request::AddContactRequest::kMale:
            std::cout << "性别：male" << std::endl;
            break;
        case request::AddContactRequest::kFemale:
            std::cout << "性别：female" << std::endl;
            break;
        case request::AddContactRequest::GENDER_NOT_SET:
            std::cout << "性别：未设置" << std::endl;
            break;
        default:
            std::cout << "未知错误" << std::endl;
            break;
        }
        for (auto &phone : request.phones())
        {
            int j = 1;
            std::cout << "电话" << j++ << ": " << phone.number();
            std::cout << " (" << phone.PhoneType_Name(phone.type()) << ")" << std::endl;
        }
        if (request.remarks_size())
        {
            std::cout << "备注信息: " << std::endl;
        }
        for (auto it = request.remarks().cbegin(); it != request.remarks().cend();
             ++it)
        {
            std::cout << " " << it->first << ": " << it->second << std::endl;
        }
    }
    void buildPeopleInfo(contacts::PeopleInfo *people, request::AddContactRequest &request) const
    {
        // 生成唯一UID
        std::string uid = Utlis::generate_hex(10);
        people->set_uid(uid);
        people->set_name(request.name());
        people->set_age(request.age());
        switch (request.gender_case())
        {
        case request::AddContactRequest::kMale:
            people->set_male("male");
            break;
        case request::AddContactRequest::kFemale:
            people->set_female("female");
            break;
        default:
            break;
        }
        for (auto &phone : request.phones())
        {
            request::Phone *phone_ptr = request.add_phones();
            phone_ptr->set_number(phone.number());
            switch (phone.type())
            {
            case request::Phone::PhoneType::Phone_PhoneType_MP:
                phone_ptr->set_type(request::Phone::PhoneType::Phone_PhoneType_MP);
                break;
            case request::Phone::PhoneType::Phone_PhoneType_TEL:
                phone_ptr->set_type(request::Phone::PhoneType::Phone_PhoneType_TEL);
                break;
            default:
                break;
            }
        }

        // 拷贝备注信息
        Utlis::map_copy(people->mutable_remark(), request.remarks());
    }
    void buildFindOneContactResponse(const contacts::PeopleInfo &people, response::FindOneContactResponse *response) const
    {
        if (response == nullptr)
        {
            return;
        }
        response->mutable_base()->set_success(true);
        response->set_uid(people.uid());
        response->set_name(people.name());
        response->set_age(people.age());
        switch (people.gender_case())
        {
        case contacts::PeopleInfo::kMale:
            response->set_male("male");
            break;
        case contacts::PeopleInfo::kFemale:
            response->set_female("female");
            break;
            ;
        default:
            break;
        }
        // 添加电话信息
        for (auto &sphone : people.phone())
        {
            response::Phone *phone_ptr = response->add_phones();
            phone_ptr->set_number(sphone.number());
            switch (sphone.type())
            {
            case response::Phone::PhoneType::Phone_PhoneType_MP:
                phone_ptr->set_type(response::Phone::PhoneType::Phone_PhoneType_MP);
                break;
            case request::Phone::PhoneType::Phone_PhoneType_TEL:
                phone_ptr->set_type(response::Phone::PhoneType::Phone_PhoneType_TEL);
                break;
            default:
                break;
            }
        }
        // 拷贝备注信息
        Utlis::map_copy(response->mutable_marks(), people.remark());
    }
    void buildFindAllContactsResponse(contacts::Contacts &contacts, response::FindAllContactsResponse *rsp) const
    {
        if (rsp == nullptr)
        {
            return;
        }
        rsp->mutable_base()->set_success(true);
        for (auto it = contacts.contacts().cbegin(); it !=contacts.contacts().cend();++it)
        {
            response::PeopleInfo *people = rsp->add_contacts();
            people->set_uid(it->first);
            people->set_name(it->second.name());
        }
    }

    ContactMapper conmapper; // 通讯录持久化
    // 添加一个联系人
    void add(request::AddContactRequest &req, response::AddContactResponse *rep) const
    {
        // 打印日志
        printAddContactRequest(req);

        // 读取contacts.bin文件
        contacts::Contacts contacts;
        conmapper.SelectContact(&contacts);

        // 转化为存入文件的对象
        // 为新存入文件的数据开辟空间
        google::protobuf::Map<std::string, contacts::PeopleInfo> *contact_map = contacts.mutable_contacts();
        contacts::PeopleInfo people;

        // 构建people结构
        buildPeopleInfo(&people, req);
        contact_map->insert({people.uid(), people});

        // 向磁盘写入新的文件
        conmapper.InsertContact(contacts);

        // 构建响应信息
        rep->set_uid(people.uid());
        rep->mutable_base()->set_success(true);
        rep->mutable_base()->set_err_desc("添加联系人成功");

        std::cout << "---> (ContactsServer::add) Success to write contacts." << std::endl;
    }

    // 删除一个联系人
    void del(request::DelContactRequest &req, response::DelContactRequest *rep) const
    {
        // 打印⽇志
        std::cout << "---> (ContactsServer::del) DelContactRequest: uid: " << req.uid() << std::endl;

        // 读取contacts.bin文件
        contacts::Contacts contacts;
        conmapper.SelectContact(&contacts);

        // 删除数据
        // 判断是否存在相应的UID,如果不存在就构建响应
        if (contacts.contacts().find(req.uid()) == contacts.contacts().end())
        {
            std::cout << "---> (ContactsServer::del) not find uid: " << req.uid() << std::endl;
            rep->set_uid(req.uid());
            rep->mutable_base()->set_success(false);
            rep->mutable_base()->set_err_desc("not find uid");
            return;
        }
        // 如果存在就删除用户
        contacts.mutable_contacts()->erase(rep->uid());
        // 写入到磁盘中
        conmapper.InsertContact(contacts);

        // 构建响应
        rep->set_uid(req.uid());
        rep->mutable_base()->set_success(true);
        rep->mutable_base()->set_err_desc("删除成功");
        // 打印⽇志
        std::cout << "---> (ContactsServer::del) Success to del contact, uid: " << req.uid() << std::endl;
    }

    // 查找一个联系人
    void findone(request::FindOneContactRequest &req, response::FindOneContactResponse *rep) const 
    {

        // 打印⽇志
        std::cout << "---> (ContactsServer::findOne) FindOneContactRequest: uid: " << req.uid() << std::endl;

        // 读取contacts.bin文件
        contacts::Contacts contacts;
        conmapper.SelectContact(&contacts);

        // 判断是否存在相应的UID,如果不存在就构建响应
        if (contacts.contacts().find(req.uid()) == contacts.contacts().end())
        {
            std::cout << "---> (ContactsServer::del) not find uid: " << req.uid() << std::endl;
            rep->set_uid(req.uid());
            rep->mutable_base()->set_success(false);
            rep->mutable_base()->set_err_desc("not find uid");
            return;
        }

        // 如果有对应的uid
        const google::protobuf::Map<std::string, contacts::PeopleInfo> &contacts_map = contacts.contacts();
        auto it = contacts_map.find(req.uid());
        buildFindOneContactResponse(it->second, rep);

        // 打印⽇志
        std::cout << "---> (ContactsServer::findOne) find uid: " << req.uid() << std::endl;
    }

    void findall(response::FindAllContactsResponse *rep) const 
    {
        // 打印⽇志
        std::cout << "---> (ContactsServer::findAll) " << std::endl;
        // 读取contacts.bin文件
        contacts::Contacts contacts;
        conmapper.SelectContact(&contacts);
        buildFindAllContactsResponse(contacts, rep);
    }
};